


import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Random;
import java.util.Set;

public class RandomWalk {

	private HashMap<Integer, HashMap<Integer, Integer>> npList;
	private HashMap<Integer, HashMap<Integer, Integer>> contextList;
	private HashMap<Integer, ArrayList<Integer>> probability;
	private HashMap<Integer, Integer> reachedNum;
	private HashMap<Integer, Double> prob;
	public final static int numtimes = 100000;
	public final static int threshold = 5;
	public final static double miniSum = 6E-14;
	private boolean shouldstop = false;

	// public static int counter = 0;

	public RandomWalk() {
		npList = new HashMap<Integer, HashMap<Integer, Integer>>();
		prob = new HashMap<Integer, Double>();
		contextList = new HashMap<Integer, HashMap<Integer, Integer>>();
		probability = new HashMap<Integer, ArrayList<Integer>>();
		reachedNum = new HashMap<Integer, Integer>();
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		RandomWalk rw = new RandomWalk();
		rw.readNP(Config.matrix1Path);
		System.out.println("load file 1 finished!");
		rw.readContext(Config.matrix2Path);
		System.out.println("load file 2 finished!");
		 rw.readProbability(Config.contextPath);
		//rw.readProbability();
		System.out.println("context load ok");
		//long startTime=System.nanoTime();
		System.out.println("load file finished!");
		
		
	for(int i = 0;i<args.length;i++){	
		int np = Integer.parseInt(args[i]);
System.out.print(np);
		rw.multiiteration(20, np);
}
		
		
		
		// rw.walk(2, numtimes);
		// for (int i = 0; i <= 100; i++) {
		// rw.walk(2, numtimes);
		// if (i % 10 == 0) {
		// //rw.printRes(i);
		// }
		// }
		

	}

	public void readProbability() {
		double p = 1.0 / npList.size();
		for (int i = 1; i <= npList.size(); i++) {
			prob.put(i, p);
		}
	}

	public void multiiteration(int iteration, int np) {
		shouldstop = false;
		for (int j = 0; j < iteration; j++) {
			if(shouldstop){
				printProb(np);
				break;
			}
			System.out.println("============================= iteration:" + j	+ " =========================================");
			walk(np, numtimes, j);

			outputNP(np, j);

		}
	}

	public void printProb(int np) {
		try {
			String folderPath = Config.dataFolderPath;
			PrintWriter pw = new PrintWriter(folderPath+np);
			
			for(Entry<Integer, Double> e: prob.entrySet()){
				pw.println(e.getKey()+"\t" + e.getValue());
			}
			pw.flush();
			pw.close();
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void walk(int noun, int numtimes, int iteration) {
		reachedNum.clear();

		for (int i = 0; i < numtimes; i++) {

			int context = getRandomedContextId(noun);
			// System.out.println("c=" + context);
			int np = chooseNP(context);
			// System.out.println("n=" + np);

			saveNPNumber(np);
		}
		updateWeights();
			
		if (iteration >= 5 && iteration%5 == 0) {
			eliminateNP(iteration);
		}
	}

	public void outputNP(int np, int iteration) {
		try {
			PrintWriter pw = new PrintWriter(np + "_iteration" + iteration
					+ ".txt");
			Set<Integer> keys = reachedNum.keySet();
			ArrayList<Integer> keyarray = new ArrayList<Integer>(keys);

			Collections.sort(keyarray, new RWComparator(reachedNum));
			for (int i = 0; i < keyarray.size(); i++) {
				pw.println(keyarray.get(i) + " "
						+ reachedNum.get(keyarray.get(i)));
			}
			pw.flush();
			pw.close();
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	public void eliminateNP(int iteration) {
		Set<Entry<Integer, Integer>> set = reachedNum.entrySet();
		int sum = 0;

		try {
			PrintWriter pw = new PrintWriter("removeNP_" + iteration + ".txt");
			for (Entry<Integer, Integer> e : set) {
				// System.out.println(e);
				if (e.getValue() < threshold) {
					int np = e.getKey();
					pw.println(np);
					// System.out.println(np);
					// contextList.remove(np);

					HashMap<Integer, Integer> clist = contextList.get(np);
					// System.out.println(clist);
					for (Iterator<Entry<Integer, Integer>> it = clist
							.entrySet().iterator(); it.hasNext();) {
						Entry<Integer, Integer> e2 = it.next();
						int contextID = e2.getKey();
						// System.out.println(contextID);

						HashMap<Integer, Integer> np_list = npList
								.get(contextID);
						// System.out.println(np_list);
						np_list.remove(np);
						
						//sum++;

						// System.out.println(np_list);
					}
					sum++;
				}

			}
			System.out.println("remove np: " + sum);
			pw.flush();
			pw.close();
		} catch (FileNotFoundException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}

		// System.out.println(npList);
		// System.out.println(contextList);
	}

	public void updateWeights() {

		// System.out
		// .println("===========================================================================================");
		HashMap<Integer, Double> newProb = new HashMap<Integer, Double>();
		for (int i = 1; i <= npList.size(); i++) {
			newProb.put(i, 0.);
		}
		// System.out.println(newProb);

		int timesSum = 0;
		for (Iterator<Entry<Integer, Integer>> iter = reachedNum.entrySet()
				.iterator(); iter.hasNext();) {

			Entry<Integer, Integer> entry = iter.next();
			int np = entry.getKey();
			int reachedTimes = entry.getValue();
			// System.out.println("np: " + np + " times:" + reachedTimes);
			HashMap<Integer, Integer> contexts = contextList.get(np);

			for (Iterator<Entry<Integer, Integer>> it2 = contexts.entrySet()
					.iterator(); it2.hasNext();) {
				Entry<Integer, Integer> e2 = it2.next();
				int c = e2.getKey();
				// System.out.println(c);

				newProb.put(c, newProb.get(c) + reachedTimes);
				timesSum += reachedTimes;
			}

		}

		// System.out.println(newProb);
		// System.out.println(timesSum);
		for (Iterator<Entry<Integer, Double>> it = newProb.entrySet()
				.iterator(); it.hasNext();) {

			Entry<Integer, Double> e = it.next();
			// int c = (Integer) e.getKey();
			double number1 = e.getValue();
			double newNumber = number1 / timesSum;
			e.setValue(newNumber);
		}

		// System.out.println(prob);
		// System.out.println(newProb);
		double sum = 0;
		for (Iterator<Entry<Integer, Double>> it = prob.entrySet().iterator(); it
				.hasNext();) {
			Entry<Integer, Double> e = it.next();
			int c = e.getKey();
			double oldValue = e.getValue();
			double newValue = newProb.get(c);

			sum += (oldValue - newValue) * (oldValue - newValue);

		}

		double diff = sum / npList.size();

		System.out.println("sum of prob difference = " + diff);
		if (diff < miniSum) {
			System.out.println("finished all task");
			shouldstop = true;
			return;

		} else {
			prob = newProb;
		}
		// System.out.println(prob);
	}

	public void saveNPNumber(int np) {
		if (reachedNum.containsKey(np)) {
			reachedNum.put(np, reachedNum.get(np) + 1);

		} else {
			reachedNum.put(np, 1);
		}
		// System.out.println(reachedNum);
	}

	public int chooseNP(int context) {
		HashMap<Integer, Integer> nps = npList.get(context);

		Set<Integer> npss = nps.keySet();
		ArrayList<Integer> nparray = new ArrayList<Integer>(npss);
		// System.out.println(nparray);
		Random r = new Random();
		int rn = r.nextInt(nparray.size());

		return nparray.get(rn);

	}

	// public int chooseContext(int np) {
	// ArrayList<Integer> randomProb = probability.get(np);
	// int size = randomProb.size();
	// Random r = new Random();
	// int randomNum = r.nextInt(size);
	// return randomProb.get(randomNum);
	//
	// }

	public void readProbability(String filename) {

		try {
			// HashMap<Integer, Double> prob = new HashMap<Integer, Double>();
			BufferedReader br = new BufferedReader(new FileReader(filename));
			String line;

			while ((line = br.readLine()) != null) {
				// System.out.println(line);
				String[] str = line.split("\\s+");

				int context = Integer.parseInt(str[0]);
				double p = Double.parseDouble(str[1]);
				prob.put(context, p);

			}

		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		// System.out.println(prob);
	}

	public int getRandomedContextId(int npId) {

		HashMap<Integer, Integer> result = contextList.get(npId);

		ArrayList<Integer> randomSet = new ArrayList<Integer>();
		for (Iterator<Entry<Integer, Integer>> iter = result.entrySet()
				.iterator(); iter.hasNext();) {
			Entry<Integer, Integer> entry = iter.next();
			double p = prob.get(entry.getKey());
			for (int i = 0; i < p * 100; i++) {
				randomSet.add(entry.getKey());
			}

		}

		// System.out.println(randomSet);
		Random r = new Random();
		int randomNum = r.nextInt(randomSet.size());
		return randomSet.get(randomNum);

	}

	public void readContext(String filename) {

		try {
			BufferedReader br = new BufferedReader(new FileReader(filename));

			int npNum = 0;
			HashMap<Integer, Integer> context = null;
			String line;

			while ((line = br.readLine()) != null) {
				String[] str = line.split("\\s+");
				int npNumber = Integer.parseInt(str[0]);

				if (npNumber != npNum) {
					contextList.put(npNum, context);
					context = new HashMap<Integer, Integer>();
					npNum = npNumber;
				}

				context.put(Integer.parseInt(str[1]), Integer.parseInt(str[2]));

			}
			br.close();
			contextList.remove(0);
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NumberFormatException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		// System.out.println(contextList);

	}

	public void readNP(String filename) {

		try {
			BufferedReader br = new BufferedReader(new FileReader(filename));
			String line;
			int contextNum = 0;
			HashMap<Integer, Integer> np = null;
			while ((line = br.readLine()) != null) {

				String[] str = line.split("\\s+");

				// System.out.println(str[0]);
				int c = Integer.parseInt(str[1]);
				// System.out.println(c);
				if (c != contextNum) {
					npList.put(contextNum, np);
					np = new HashMap<Integer, Integer>();
					contextNum = c;
				}

				np.put(Integer.parseInt(str[0]), Integer.parseInt(str[2]));

			}
			br.close();
			npList.remove(0);

		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		// System.out.println(npList);
	}

}
